package com.jamal2362.apktool.task;

import android.content.Context;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import androidx.appcompat.app.AlertDialog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import com.jamal2362.apktool.R;
import com.jamal2362.apktool.fragment.files.Refreshable;
import com.jamal2362.apktool.util.FileUtils;
import com.jamal2362.apktool.util.MUtil;
import com.jamal2362.apktool.util.Manifest;
import com.jamal2362.apktool.util.Settings;
import com.jamal2362.apktool.util.TextUtil;
import android.widget.TextView;

public class CompressTask extends AsyncTask<File, String, Boolean>
{
	private final String[] ignoreStarts = new String[]{"assets/ugc", "assets/yandexnavi/fonts/tiles", "res/raw/netdisk", "assets/yandexnavi/fonts/", "res/raw/langid.data", "res/raw/joda", "assets/adp", "assets/js-modules/UNBUNDLE", "res/raw/estool", "res/raw/feature", "res/raw/irlocaldata", "assets/sound-strings/", "res/raw/selection", "res/raw/sb", "res/raw/guides", "res/raw/metadata.json", "res/raw/sm", "assets/cuisine-strings/", "res/raw/fill", "res/raw/transform", "assets/metadata.json", "res/raw/copic", "res/raw/layers", "res/raw/dav", "res/raw/test", "res/raw/timelapse", "res/raw/pulsar", "res/raw/cuscs", "res/raw/gtm", "res/raw/megviifacepp", "assets/countries-strings/", "assets/services/", "res/raw/ep", "assets/ABBYY.license", "res/raw/bnbp", "libs/", "res/raw/tw", "res/raw/bear.tiff", "res/raw/yvideo", "res/raw/spki"};
	private final String[] ignoreEnds = new String[]{".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp2", ".mp3", ".ogg", ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", ".amr", ".awb", ".wma", ".wmv", ".avc", ".der", ".pfx", ".kml", ".pic", ".bc", ".key", ".glsl", ".plugin", ".p12", ".dat", ".cer", ".pb", ".bks", ".woff2", ".res", "/thumbnail", ".binarypb", ".bin", ".dict", ".zip", ".pk8", ".mov", ".crt"};
	private Context context;
	private AlertDialog progress;
	private Refreshable refresh;
	private boolean redirect;

	public CompressTask(Context ctx, Refreshable refr)
	{
		this.context = ctx;
		this.refresh = refr;
		this.redirect = false;
	}

	@Override
	protected void onPreExecute()
	{
		LayoutInflater inflater = LayoutInflater.from(context);
		View view = inflater.inflate(R.layout.search_progress, null);
		TextView tview = view.findViewById(R.id.searchprogressTextView1);
		tview.setText(R.string.mplease_wait);
		progress = new AlertDialog.Builder(context)
			.setView(view)
			.setCancelable(false)
			.create();
		progress.show();
	}

	@Override
	protected Boolean doInBackground(File[] p1)
	{
		for (File file : p1)
		{
			String out = getOutFile(file, "_temp");
			if (out == null)
				continue;
			try
			{
				final Manifest mf = new Manifest(file);
				final int minSdk = mf.getMinSdkVersion();
				final File opapk = optimizeApk(file.getAbsolutePath(), out);
				SignUtil.loadKey(context, new SignUtil.LoadKeyCallback(){
						@Override
						public void call(SignUtil signTool)
						{
							String result = getOutFile(opapk, "_optimize");
							signTool.sign(opapk, new File(result), minSdk);
						}
					});
				opapk.delete();
			}
			catch (Exception e)
			{}
		}
		return true;
	}

	@Override
	protected void onPostExecute(Boolean result)
	{
		progress.cancel();
		if (redirect)
		{
			Runnable go = new Runnable()
			{
				@Override
				public void run()
				{
					refresh.refresh(new File(Settings.output_directory));
				}
			};
			MUtil.createDialog(context, context.getString(R.string.complete) + "!", R.string.go_to, go);
		}
		else
		{
			refresh.refresh();
		}
		super.onPostExecute(result);
	}

	private String getOutFile(File f, String suff)
	{
		String dir = f.getParent();
		String name = f.getName();
		boolean noaccess = !f.getParentFile().canWrite();
		if (noaccess)
		{
			dir = Settings.output_directory;
			if (dir == null)
			{
				TextUtil.st(context, context.getString(R.string.output_directory_not_set));
				return null;
			}
			File d =  new File(dir);
			if (!d.exists() && !d.mkdirs())
			{
				TextUtil.st(context, context.getString(R.string.output_directory_not_extsts, dir));
				return null;
			}
			if (!d.isDirectory())
			{
				TextUtil.st(context, context.getString(R.string.not_directory, dir));
				return null;
			}
			redirect = true;
		}
		name = FileUtils.genNameApk(context, dir, name, suff, 0);
		return dir + File.separator + name;
	}

	private File optimizeApk(String srcApk, String targetApk) throws IOException
	{
		ZipInputStream zin = new ZipInputStream(new FileInputStream(srcApk));
		ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(targetApk));
		zout.setLevel(Deflater.DEFLATED);
		ZipEntry entry;
		byte[] buffer = new byte[1024];
		while ((entry = zin.getNextEntry()) != null)
		{
			String ename = entry.getName();

			ZipEntry outEntry = new ZipEntry(ename);
			if (isIgnore(ename))
			{
				outEntry.setMethod(ZipEntry.STORED);
				outEntry.setSize(entry.getSize());
				outEntry.setCrc(entry.getCrc());
			}
			else
			{
				outEntry.setMethod(ZipEntry.DEFLATED);
			}
			outEntry.setCompressedSize(entry.getSize());
			zout.putNextEntry(outEntry);
			int length;
			while ((length = zin.read(buffer, 0, buffer.length)) > 0)
			{
				zout.write(buffer, 0, length);
			}
			zout.flush();
			zout.closeEntry();
		}
		zin.closeEntry();
		zin.close();
		zout.flush();
		zout.close();
		return new File(targetApk);
	}

	private boolean isIgnore(String name)
	{
		if (name.toLowerCase().startsWith("r/"))
		{
			return true;
		}
		for (String start : ignoreStarts)
		{
			if (name.startsWith(start))
			{
				return true;
			}
		}
		if (name.startsWith("res/raw") || name.startsWith("assets/"))
		{
			for (String end : ignoreEnds)
			{
				if (name.endsWith(end))
				{
					return true;
				}
			}
		}
		return false;
	}
}
